#include "cbb_ph_mb_master.h"
#include <string.h>

PH_REG_DEF(cbb_mb_master, PH_MB_Master_t)

PH_RET_t
cbb_mb_set_data(PH_t* pstSelf, MB_Master_Data_t* pstData){

    // 校验参数
    if(NULL == pstSelf || NULL == pstData || NULL == pstSelf->pvFeature) return PH_ERR;

    // 获取modbus上下文
    PH_MB_Master_t* pstModbus = GET_PH(pstSelf, PH_MB_Master_t);

    // 复制数据到缓存
    for(int i=0;i<pstData->u16RegCount;i++) pstModbus->u16Cache[i] = pstData->pu16Data[i];
    
    // 复制数据到备份
    memcpy(&(pstModbus->stData), pstData, sizeof(MB_Master_Data_t));

    // 数据指针指向内部缓存备份
    pstModbus->stData.pu16Data = pstModbus->u16Cache;
    
    // 返回成功
    return PH_OK;
}

PH_RET_t 
cbb_mb_master_build(PH_t* pstSelf, PH_Buf_t* pstTxBuffer){

    // 校验参数
    if(NULL == pstTxBuffer || NULL == pstTxBuffer->pu8Buffer || 4 > pstTxBuffer->u32BufferLen) return PH_ERR;

    // 校验参数
    if(NULL == pstSelf || NULL == pstSelf->pvFeature || NULL == pstSelf->pfnAppend) return PH_ERR;

    // 获取modbus上下文
    PH_MB_Master_t* pstModbus = GET_PH(pstSelf, PH_MB_Master_t);

    // 获取数据
    MB_Master_Data_t* pstData = &(pstModbus->stData);

    // 报文长度
    uint32_t u32Len = 0;

    // 提取数据
    uint8_t* pu8Request     = pstTxBuffer->pu8Buffer;
    uint8_t u8Addr          = pstData->u8Addr;
    uint8_t u8FuncCode      = pstData->u8FuncCode;
    uint16_t u16StartReg    = pstData->u16StartReg;
    uint16_t u16RegCount    = pstData->u16RegCount;
    
    // 填充报文
    pu8Request[u32Len++] = u8Addr;
    pu8Request[u32Len++] = u8FuncCode;
    pu8Request[u32Len++] = (u16StartReg >> 8) & 0xFF;
    pu8Request[u32Len++] = u16StartReg & 0xFF;

    if(u8FuncCode == 0x03 || u8FuncCode == 0x04) {

        // 判断长度是否足够
        if(8 > pstTxBuffer->u32BufferLen) return PH_ERR;

        // 填充报文
        pu8Request[u32Len++] = (u16RegCount >> 8) & 0xFF;
        pu8Request[u32Len++] = u16RegCount & 0xFF;
    }
    else if(u8FuncCode == 0x06) {

        // 判断长度是否足够
        if(0 == u16RegCount || 8 > pstTxBuffer->u32BufferLen) return PH_ERR;

        // 获取数据
        uint16_t u16Data = pstData->u16Data;

        // 填充报文
        pu8Request[u32Len++] = (u16Data >> 8) & 0xFF;
        pu8Request[u32Len++] = u16Data & 0xFF;
    }
    else if(u8FuncCode == 0x10) {
    
        // 判断长度是否足够
        if(0 == u16RegCount || (uint16_t)(9 + 2*u16RegCount) > pstTxBuffer->u32BufferLen) return PH_ERR;

        // 填充报文
        pu8Request[u32Len++] = (u16RegCount >> 8) & 0xFF;
        pu8Request[u32Len++] = u16RegCount & 0xFF;
        pu8Request[u32Len++] = u16RegCount * 2;

        for(int i=0;i<u16RegCount;i++)
        {
            uint16_t u16Data = pstData->pu16Data[i];
            pu8Request[u32Len++] = (u16Data >> 8) & 0xFF;
            pu8Request[u32Len++] = u16Data & 0xFF;
        }
    }
    else return PH_ERR;

    // 追加crc校验
    uint8_t u8Ret = pstSelf->pfnAppend(pu8Request, &u32Len);
    if(!u8Ret) return PH_ERR;

    // 更新长度返回成功
    pstTxBuffer->u32DataLen = u32Len;
    return PH_OK;
}

PH_RET_t 
cbb_mb_master_parse(PH_t* pstSelf, PH_Buf_t* pstRxBuffer){

    // 校验参数
    if(NULL == pstRxBuffer || NULL == pstRxBuffer->pu8Buffer || 7 > pstRxBuffer->u32DataLen) return PH_ERR;

    // 校验参数
    if(NULL == pstSelf || NULL == pstSelf->pvFeature || NULL == pstSelf->pfnCheck) return PH_ERR;

    // 校验CRC
    uint8_t u8Ret = pstSelf->pfnCheck(pstRxBuffer->pu8Buffer, pstRxBuffer->u32DataLen);
    if(!u8Ret) return PH_ERR;

    // 获取modbus上下文
    PH_MB_Master_t* pstModbus = GET_PH(pstSelf, PH_MB_Master_t);

    // 获取数据
    MB_Master_Data_t* pstData = &(pstModbus->stData);

    // 提取数据
    uint8_t* pu8Response    = pstRxBuffer->pu8Buffer;
    uint8_t u8Addr          = pu8Response[0];
    uint8_t u8FuncCode      = pu8Response[1];

    // 判断参数与上一次是否相符
    if(u8Addr != pstData->u8Addr || u8FuncCode != pstData->u8FuncCode) return PH_ERR;

    // 解析数据
    if(u8FuncCode == 0x03 || u8FuncCode == 0x04) {

        // 获取寄存器数量
        uint16_t u16RegCount = pu8Response[2] / 2;

        // 判断报文长度是否符合
        if((uint16_t)(5 + 2*u16RegCount) != pstRxBuffer->u32DataLen) return PH_ERR;

        // 判断参数与上一次是否相符
        if(u16RegCount != pstData->u16RegCount) return PH_ERR;

        // 获取数据源
        uint16_t* pu16Src = u8FuncCode == 0x03? pstModbus->pu16HoldingRegs : pstModbus->pu16InputRegs;
        uint16_t u16BufSize = u8FuncCode == 0x03? pstModbus->u16HoldingRegsSize : pstModbus->u16InputRegsSize;
        
        // 判断数据源是否存在以及长度是否足够
        if(NULL == pu16Src || pstData->u16StartReg + u16RegCount > u16BufSize) return PH_ERR;

        // 解析数据
        for(int i=0;i<u16RegCount;i++){
            uint16_t u16Data = pu8Response[3 + 2*i] * 256 + pu8Response[3 + 2*i + 1];
            pstModbus->pu16HoldingRegs[pstData->u16StartReg + i] = u16Data;
        }

    }
    else if(u8FuncCode == 0x06) {
        // 获取寄存器数量
        uint16_t u16StartReg    = pu8Response[2] * 256 + pu8Response[3];
        uint16_t u16Data        = pu8Response[4] * 256 + pu8Response[5];

        // 判断报文长度是否符合
        if( 8 != pstRxBuffer->u32DataLen) return PH_ERR;
        
        // 判断参数与上一次是否相符
        if(u16Data != pstData->u16Data || u16StartReg != pstData->u16StartReg) return PH_ERR;

        // 获取数据源
        uint16_t* pu16Src = pstModbus->pu16HoldingRegs;
        uint16_t u16BufSize = pstModbus->u16HoldingRegsSize;
        
        // 判断数据源是否存在以及长度是否足够
        if(NULL == pu16Src || u16StartReg > u16BufSize) return PH_ERR;

        // 解析数据
        pstModbus->pu16HoldingRegs[u16StartReg] = u16Data;
        
    }
    else if(u8FuncCode == 0x10) {

        // 获取寄存器数量
        uint16_t u16StartReg = pu8Response[2] * 256 + pu8Response[3];
        uint16_t u16RegCount = pu8Response[4] * 256 + pu8Response[5];

        // 判断报文长度是否符合
        if( 8 != pstRxBuffer->u32DataLen) return PH_ERR;
        
        // 判断参数与上一次是否相符
        if(u16RegCount != pstData->u16RegCount) return PH_ERR;

        // 获取数据源
        uint16_t* pu16Src = pstModbus->pu16HoldingRegs;
        uint16_t u16BufSize = pstModbus->u16HoldingRegsSize;
        
        // 判断数据源是否存在以及长度是否足够
        if(NULL == pu16Src || u16StartReg + u16RegCount > u16BufSize) return PH_ERR;

        // 解析数据
        for(int i=0;i<u16RegCount;i++) {
            pu16Src[u16StartReg + i] = pstModbus->u16Cache[i];
        }

        // 重置缓存
        memset(pstModbus->u16Cache, 0, sizeof(pstModbus->u16Cache));
    }
    else return PH_ERR;

    // 返回成功
    return PH_OK;
}
